package com.example.activiti.service;

import org.activiti.engine.*;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.identity.Group;
import org.activiti.engine.identity.User;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

/**
 * @Author: 程荣凯
 * @Date: 2018/9/25 17:06
 */
@Service
public class ProcessUtilService {
    /**
     * 获取默认流程引擎
     */
    private ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    /**
     * 默认流程文件存储路径
     */
    private static final String DEFAULT_PATH = "process/process.zip";
    /**
     * 流程引擎创建成功标志
     */
    private volatile int hasCreateEngine = 0;

    /**
     * 创建流程引擎（重新生成数据库表）
     */
    public synchronized void createProcessEngineByCfgXml() {
        if(hasCreateEngine == 0){
            ProcessEngineConfiguration cfg = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("process/activiti.cfg.xml");
            ProcessEngine engine = cfg.buildProcessEngine();
            hasCreateEngine++;
            System.out.println("流程引擎启动成功,启动时间为"+new Date());
        }
    }

    /**
     * 发布流程定义
     *
     * @param processPath        流程定义文件路径
     * @param processDiagramPath 流程定义图片路径
     * @return 结果
     */
    public  boolean publishProcess(String processPath, String processDiagramPath) {
        boolean result = false;
        if (null != processPath) {
            if (ResourceUtils.isUrl(processPath)) {
                try {
                    File file = ResourceUtils.getFile(processPath);
                    if (file.exists()) {
                        return false;
                    }
                    RepositoryService repositoryService = processEngine.getRepositoryService();
                    DeploymentBuilder builder = repositoryService.createDeployment();
                    builder.addClasspathResource(processPath);
                    if (null != processDiagramPath) {
                        builder.addClasspathResource(processDiagramPath);
                    }
                    Deployment deploy = builder.deploy();
                    String id = deploy.getId();
                    if (null != id) {
                        result = true;
                    }
                } catch (FileNotFoundException ignored) {
                }
            }
        }
        return result;
    }

    /**
     * 发布所有流程定义
     * @return
     */
    public  boolean publishProcessAll() {
        boolean result = false;
        try {
            File file = ResourceUtils.getFile(DEFAULT_PATH);
            InputStream inputStream = new FileInputStream(file);
            ZipInputStream zipInputStream = new ZipInputStream(inputStream);
            Deployment deployment = processEngine.getRepositoryService()
                    .createDeployment()
                    .addZipInputStream(zipInputStream)
                    .deploy();
            System.out.println("部署ID：" + deployment.getId());
            System.out.println("部署时间：" + deployment.getDeploymentTime());
            result = true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            return result;
        }
    }

    /**
     * 查询系统中所有的流程定义
     *
     * @return
     */
    public List<ProcessDefinition> queryProcessList() {
        List<ProcessDefinition> list = processEngine.getRepositoryService()
                .createProcessDefinitionQuery()
                // 查询条件
                .orderByProcessDefinitionVersion().desc()
                .list();
        return list;
    }

    /**
     * 根据流程定义ID删除流程定义
     * @param processDefinitionId 流程定义ID
     * @param cascade 是否级联删除(默认为false)
     */
    public  void deleteProcessDefinition(String processDefinitionId,boolean cascade){
        //得到repositoryService
        RepositoryService repositoryService = processEngine
                .getRepositoryService();
        //根据流程定义id查询部署id
        ProcessDefinition processDefinition = repositoryService
                .createProcessDefinitionQuery()
                .processDefinitionId(processDefinitionId)
                .singleResult();
        //流程定义所属部署id
        String deploymentId = processDefinition.getDeploymentId();

        repositoryService.deleteDeployment(deploymentId,cascade);
        System.out.println("流程定义删除成功");
    }

    /**
     * 根据流程定义Key删除流程定义
     * @param processDefinitionKey 流程定义Key
     * @param cascade 是否级联删除(默认为false)
     */
    public  void deleteProcessDefinitionByKey(String processDefinitionKey,boolean cascade){
        //得到repositoryService
        RepositoryService repositoryService = processEngine
                .getRepositoryService();
        //根据流程定义id查询部署id
        ProcessDefinition processDefinition = repositoryService
                .createProcessDefinitionQuery()
                .processDefinitionKey(processDefinitionKey)
                .singleResult();
        //流程定义所属部署id
        String deploymentId = processDefinition.getDeploymentId();
        repositoryService.deleteDeployment(deploymentId,cascade);
        System.out.println("流程定义删除成功");

    }

    /**
     * 创建流程实例
     *
     * @param processDefKey 流程定义Key
     * @return 流程实例ID
     */
    public  String startProcessInstByKey(String processDefKey) {
        ProcessInstance processInstance = processEngine.getRuntimeService()
                .startProcessInstanceByKey(processDefKey);
        System.out.println("流程实例ID:" + processInstance.getId());
        System.out.println("流程定义ID:" + processInstance.getProcessDefinitionId());
        return processInstance.getId();
    }

    /**
     * 创建流程实例
     *
     * @param processDefId 流程定义ID
     * @return 流程实例ID
     */
    public  String startProcessInstById(String processDefId) {
        ProcessInstance processInstance = processEngine.getRuntimeService()
                .startProcessInstanceById(processDefId);
        System.out.println("流程实例ID:" + processInstance.getId());
        System.out.println("流程定义ID:" + processInstance.getProcessDefinitionId());
        return processInstance.getId();
    }

    /**
     * 设置流程变量
     * @param processInstId 流程实例ID
     * @param variables
     * @return
     */
    public  boolean setProcessVariable(String processInstId,Map<String,Object> variables) {
        boolean result = false;
        processEngine.getRuntimeService().setVariables(processInstId,variables);
        System.out.println("设置流程变量成功");
        result = true;
        return result;
    }

    /**
     * 设置流程变量(单个)
     * @param processInstId 流程实例ID
     * @param key 流程变量名称
     * @param value 流程变量值
     * @return
     */
    public  boolean setProcessVariableSingle(String processInstId,String key,String value) {
        boolean result = false;
        processEngine.getRuntimeService().setVariable(processInstId,key,value);
        System.out.println("设置流程变量成功");
        result = true;
        return result;
    }

    /**
     * 删除流程实例
     * @param processInstId 流程实例ID
     * @param reason 原因
     */
    public  void deleteProcessInst(String processInstId,String reason){
        processEngine.getRuntimeService().deleteProcessInstance(processInstId,reason);
        System.out.println("删除流程实例成功");
    }

    /**
     * 挂起流程实例
     * @param processInstId 流程实例ID
     */
    public  void suspendProcessInst(String processInstId){
        processEngine.getRuntimeService().suspendProcessInstanceById(processInstId);
        System.out.println("挂起流程实例成功");
    }

    /**
     * 激活流程实例
     * @param processInstId 流程实例ID
     */
    public  void activateProcessInst(String processInstId){
        processEngine.getRuntimeService().activateProcessInstanceById(processInstId);
        System.out.println("激活流程实例成功");
    }

//    public  void terminateProcessInst(String processInstId){
//        ActivityImpl endActivity = findActivitiImpl(taskId, "end");
//        processEngine.getTaskService().
//
//    }

//    /**
//     * 完成流程活动
//     * @param activityId 活动ID
//     * @return
//     */
//    public  boolean finishActivity(String activityId){
//        processEngine.getTaskService().createTaskQuery()
//    }

    /**
     * 完成工作项
     * @param processInstId 流程实例ID
     * @param workItemId 工作项ID
     * @param userId 用户ID
     * @return
     */
    public  boolean finishWorkItem(String processInstId,String workItemId,String userId){
        TaskService taskService = processEngine.getTaskService();
        boolean result = false;
        try {

            //若不传userId表示是超级管理员操作，可直接完成
            if (userId == null){
                taskService.complete(workItemId);
            }else {
                Task task = taskService.createTaskQuery().processInstanceId(processInstId)
                        .taskId(workItemId).taskAssignee(userId).singleResult();
                //若此工作项为当前用户的工作项，则允许完成
                if (null != task){
                    taskService.complete(workItemId);
                }else {
                    System.out.println("用户"+userId+"无此操作权限");
                }
            }

            result = true;
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 回退工作项
     * @param processInstId 流程实例ID
     * @param workItemId 工作项ID
     * @param userId 用户ID
     * @return
     */
    public  boolean backWorkItem(String processInstId,String workItemId,String userId){
        TaskService taskService = processEngine.getTaskService();
        boolean result = false;
        try {

            //若不传userId表示是超级管理员操作，可直接完成
            if (userId == null){
                //设置回退连线上的条件值
                taskService.setVariable(processInstId,"back","1");
                taskService.complete(workItemId);
                //提交完成后还原条件值
                taskService.setVariable(processInstId,"back","0");
            }else {
                Task task = taskService.createTaskQuery().processInstanceId(processInstId)
                        .taskId(workItemId).taskAssignee(userId).singleResult();
                //若此工作项为当前用户的工作项，则允许完成
                if (null != task){
                    //设置回退连线上的条件值
                    taskService.setVariable(processInstId,"back","1");
                    taskService.complete(workItemId);
                    //提交完成后还原条件值
                    taskService.setVariable(processInstId,"back","0");
                }else {
                    System.out.println("用户"+userId+"无此操作权限");
                }
            }

            result = true;
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }



    /**
     * 设置备注信息(审批意见)
     * @param processInstId 流程实例ID
     * @param workItemId 工作项ID
     * @param userId 用户ID
     * @param comments 备注信息
     * @return
     */
    public  boolean setWorkItemComment(String processInstId,String workItemId,String userId,String comments){
        TaskService taskService = processEngine.getTaskService();
        boolean result = false;
        try {

            //若不传userId表示是超级管理员操作，可直接操作
            if (userId == null){
                taskService.addComment(workItemId,processInstId,comments);
            }else {
                Task task = taskService.createTaskQuery().processInstanceId(processInstId)
                        .taskId(workItemId).taskAssignee(userId).singleResult();
                //若此工作项为当前用户的工作项，则允许完成
                if (null != task){
                    taskService.addComment(workItemId,processInstId,comments);
                }else {
                    System.out.println("用户"+userId+"无此操作权限");
                }
            }

            result = true;
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 删除备注信息(审批意见)
     * @param processInstId 流程实例ID
     * @param workItemId 工作项ID
     * @param userId 用户ID
     * @param commentId 备注ID
     * @return
     */
    public  boolean deleteWorkItemComment(String processInstId,String workItemId,String userId,String commentId){
        TaskService taskService = processEngine.getTaskService();
        boolean result = false;
        try {

            //若不传userId表示是超级管理员操作，可直接操作
            if (userId == null){
                taskService.deleteComment(commentId);
            }else {
                Task task = taskService.createTaskQuery().processInstanceId(processInstId)
                        .taskId(workItemId).taskAssignee(userId).singleResult();
                //若此工作项为当前用户的工作项，则允许完成
                if (null != task){
                    taskService.deleteComment(commentId);
                }else {
                    System.out.println("用户"+userId+"无此操作权限");
                }
            }

            result = true;
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 设置流程工作项参与者
     * @param processInstId 流程实例ID
     * @param workItemId 工作项ID
     * @param assigner 参与者
     * @return
     */
    public  boolean setAssigner(String processInstId,String workItemId,String assigner){
        TaskService taskService = processEngine.getTaskService();
        boolean result = false;
        Task task = taskService.createTaskQuery().processInstanceId(processInstId)
                .taskId(workItemId).singleResult();
        taskService.setAssignee(workItemId,assigner);
        result = true;
        return result;
    }

    public  boolean setAssigners(String processInstId,String workItemId,List<String> assigners){
        boolean result = true;
        for (String assigner : assigners) {
            boolean tempResult = setAssigner(processInstId,workItemId,assigner);
            if (!tempResult){
                result = false;
            }
        }
        return result;
    }

    /**
     * 设置流程候选人
     * @param processInstId 流程实例ID
     * @param workItemId 工作项ID
     * @param candidateUser 候选人ID
     * @return
     */
    public  boolean setCandidateUser(String processInstId,String workItemId,String candidateUser){
        TaskService taskService = processEngine.getTaskService();
        boolean result = false;
        taskService.addCandidateUser(workItemId,candidateUser);
        result = true;
        return result;
    }

    /**
     * 设置流程候选组
     * @param processInstId 流程实例ID
     * @param workItemId 工作项ID
     * @param candidateGroup 候选组ID
     * @return
     */
    public  boolean setCandidateGroup(String processInstId,String workItemId,String candidateGroup){
        TaskService taskService = processEngine.getTaskService();
        boolean result = false;
        taskService.addCandidateGroup(workItemId,candidateGroup);
        result = true;
        return result;
    }


    /**
     * 新增流程用户
     * @param userId 用户ID
     * @param userName 用户名称
     * @param password 密码
     * @param email 邮箱地址
     * @return
     */
    public  boolean addActUser(String userId,String userName,String password,String email){
        boolean result =  false;
        IdentityService identityService = processEngine.getIdentityService();
        User user = identityService.newUser(userId);
        user.setId(userId);
        user.setFirstName(userName);
        user.setPassword(password);
        user.setEmail(email);
        identityService.saveUser(user);
        result = true;
        return result;
    }

    /**
     * 新增流程组
     * @param groupId 组ID
     * @param groupName 组名称
     * @param type 组类型
     * @return
     */
    public  boolean addActGroup(String groupId,String groupName,String type){
        boolean result =  false;
        IdentityService identityService = processEngine.getIdentityService();
        Group group = identityService.newGroup(groupId);
        group.setId(groupId);
        group.setName(groupName);
        group.setType(type);
        identityService.saveGroup(group);
        result = true;
        return result;
    }

    /**
     * 新增流程用户与组的关系
     * @param groupId 组ID
     * @param userId 用户ID
     * @return
     */
    public  boolean addActGroupUserLink(String groupId,String userId){
        boolean result =  false;
        IdentityService identityService = processEngine.getIdentityService();
        identityService.createMembership(userId,groupId);
        result = true;
        return result;
    }

    /**
     * 删除流程用户
     * @param userId 用户ID
     * @return
     */
    public  boolean deleteActUser(String userId){
        boolean result =  false;
        IdentityService identityService = processEngine.getIdentityService();
        identityService.deleteUser(userId);
        result = true;
        return result;
    }

    /**
     * 删除流程组
     * @param groupId 组ID
     * @return
     */
    public  boolean deleteActGroup(String groupId){
        boolean result =  false;
        IdentityService identityService = processEngine.getIdentityService();
        identityService.deleteGroup(groupId);
        result = true;
        return result;
    }

    /**
     * 删除流程用户与组的关系
     * @param groupId 组ID
     * @param userId 用户ID
     * @return
     */
    public  boolean deleteActGroupUserLink(String groupId,String userId){
        boolean result = false;
        IdentityService identityService = processEngine.getIdentityService();
        identityService.deleteMembership(userId,groupId);
        result = true;
        return result;
    }

    /**
     * 查询用户待办任务
     * @param userId 用户ID
     * @return
     */
    public List<Task> queryUndoTask(String userId){
        TaskService taskService = processEngine.getTaskService();
        List<Task> taskList = taskService.createTaskQuery().taskAssignee(userId).orderByTaskCreateTime().list();
        IdentityService identityService = processEngine.getIdentityService();
        List<Group> groupList = identityService.createGroupQuery().groupMember(userId).list();
        if (groupList != null && groupList.size()>0){
            for (Group group : groupList) {
                List<Task> list = taskService.createTaskQuery().taskCandidateGroup(group.getId()).orderByTaskCreateTime().list();
                if (null != list && list.size()>0){
                    taskList.addAll(list);
                }
            }
        }
        return taskList;
    }

    /**
     * 查询用户已办任务
     * @param userId 用户ID
     * @return
     */
    public List<HistoricTaskInstance> queryDoneTask(String userId){
        HistoryService historyService = processEngine.getHistoryService();
        List<HistoricTaskInstance> taskList = historyService.createHistoricTaskInstanceQuery()
                .taskAssignee(userId).unfinished().orderByTaskCreateTime().list();
        IdentityService identityService = processEngine.getIdentityService();
        List<Group> groupList = identityService.createGroupQuery().groupMember(userId).list();
        if (groupList != null && groupList.size()>0){
            for (Group group : groupList) {
                List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
                        .taskCandidateGroup(group.getId()).unfinished().orderByTaskCreateTime().list();
                if (null != list && list.size()>0){
                    taskList.addAll(list);
                }
            }
        }
        return taskList;
    }

    /**
     * 查询用户已办结任务
     * @param userId 用户ID
     * @return
     */
    public List<HistoricTaskInstance> queryFinishTask(String userId){
        HistoryService historyService = processEngine.getHistoryService();
        List<HistoricTaskInstance> taskList = historyService.createHistoricTaskInstanceQuery()
                .taskAssignee(userId).finished().orderByTaskCreateTime().list();
        IdentityService identityService = processEngine.getIdentityService();
        List<Group> groupList = identityService.createGroupQuery().groupMember(userId).list();
        if (groupList != null && groupList.size()>0){
            for (Group group : groupList) {
                List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
                        .taskCandidateGroup(group.getId()).finished().orderByTaskCreateTime().list();
                if (null != list && list.size()>0){
                    taskList.addAll(list);
                }
            }
        }
        return taskList;
    }

}
